#pragma once
#include "Epoller.hpp"
#include <memory>
class TcpServer
{
public:
    TcpServer():_epoller(new Epoller), _listener(new TcpSocket)
    {}
    ~TcpServer()
    {}
    void Init(int port, int backlog)
    {
        _listener->BuiltListenSockfd(port, backlog);
        int opt = 1;
        setsockopt(_listener->GetSocket(), SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt, sizeof(opt));
        _epoller->Add(_listener->GetSocket(), EPOLLIN);
    }

    bool Accepter(std::string* ip, uint16_t* port)
    {
        int sockfd = _listener->AcceptConnection(ip, port);
        if(sockfd < 0) return false;
        _epoller->Add(sockfd, EPOLLIN);
        return true;
    }

    void Hander(int n)
    {
        for(int i = 0; i < n; i++)
        {
            int fd = _rev[i].data.fd;
            int event = _rev[i].events;
            if(event & EPOLLIN)
            {
                if(fd == _listener->GetSocket())
                {
                    std::string ip; uint16_t port;
                    if(!Accepter(&ip, &port))
                        continue;
                }
                else
                {
                    char buffer[1024];
                    int n = read(fd, buffer, sizeof(buffer));
                    if(n > 0)
                    {
                        buffer[n] = 0;
                        std::cout << "fd:"<< fd << " # " << buffer <<"\n";
                        std::string ret = buffer;
                        ret += "收到";
                        write(fd, ret.c_str(), ret.size());
                    }
                    else
                    {
                        _epoller->Delete(fd);
                        close(fd); // 先从epoll中删除fd，再去关闭文件描述符，因为epoll在删除文件描述符时要求该文件描述符是有效的
                    }
                }
            }
        }
    }
    void Loop()
    {
        while(1)
        {
            int n = _epoller->Wait(_rev, 100, 0);
            switch(n)
            {
                case 0: std::cout << "没有数据\n"; break; 
                case -1: std::cout << "epoll 出错\n"; break;
                default: Hander(n); break;
            }
        }
    }
private:
    std::unique_ptr<Epoller> _epoller;
    std::unique_ptr<TcpSocket> _listener;
    uint16_t _port;
    struct epoll_event _rev[100];
};